#include "TcpClient.h"
#include "public_define.h"
#include <signal.h>
// #include <linux/tcp.h>
#include <libgen.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <netinet/tcp.h>

//类的构造函数实现
CTcpClient ::CTcpClient()
{
  m_sockfd = -1;
  // signal(SIGPIPE, SIG_IGN);
  // sigset_t set;
  // sigemptyset(&set);
  // sigaddset(&set, SIGPIPE);
  // sigprocmask(SIG_BLOCK, &set, NULL);
}

int CTcpClient::SetTcpSocketTimeout(int handle, int idle, int interval, int times)//30 10 3
{
	int keepAlive = 1;
	int retCI = setsockopt(handle, SOL_SOCKET, SO_KEEPALIVE, (void *) &keepAlive, sizeof(keepAlive));// 开启keepalive属性
	retCI = setsockopt(handle, SOL_TCP, TCP_KEEPIDLE, (void*) &idle, sizeof(idle));// 如该连接在10秒内没有任何数据往来,则进行探测
	retCI = setsockopt(handle, SOL_TCP, TCP_KEEPINTVL, (void *) &interval, sizeof(interval));// 探测时发包的时间间隔为3秒
	retCI = setsockopt(handle, SOL_TCP, TCP_KEEPCNT, (void *) &times, sizeof(times));// 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.
	(void)retCI;
  return true;
}

int	CTcpClient::SetSockSendTimeOut(
								int handle,
								const int timeoSec,
								const int timeoUsec )
{
	if(handle > 0)
	{
		struct timeval	sendTimeo;

		memset( &sendTimeo, 0x0, sizeof( timeval ) );
		sendTimeo.tv_sec = timeoSec;
		sendTimeo.tv_usec = timeoUsec;

		int	setRet = setsockopt( handle, SOL_SOCKET, SO_SNDTIMEO, ( char* )&sendTimeo, sizeof( timeval ) );

		return setRet;
	}
	return -1;

}


//连接到服务器实现
bool CTcpClient ::ConnectToServer(const std::string &host, const int &port)
{
  m_host = host;
  m_port = port;
  // SOCKET
  m_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (m_sockfd < 0)
  {
    Log_Info("socket init failed");
    return false;
  }

  SetTcpSocketTimeout(m_sockfd, 30, 10, 3);


  /*初始换结构体*/
  struct sockaddr_in sockaddr;
  bzero(&sockaddr, sizeof(sockaddr));
  sockaddr.sin_family = AF_INET;
  sockaddr.sin_addr.s_addr = inet_addr(host.c_str());
  sockaddr.sin_port = htons(port);

  //连接服务器
  if (connect(m_sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) == -1)
  {
    Log_Info("connect failed");
    close(m_sockfd);
    m_sockfd = -1;
    return false;
  }

  int ret = SetSockSendTimeOut(m_sockfd,5,0);
  (void)ret;
  Log_Info("...........connect success.............");
  return true;
}

//重连
bool CTcpClient ::ReConnectToServer()
{
  if (m_sockfd != -1)
  {
    close(m_sockfd);
    m_sockfd = -1;
  }

  // SOCKET
  m_sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (m_sockfd < 0)
  {
    Log_Info("socket init failed");
    return false;
  }

  /*初始换结构体*/
  struct sockaddr_in sockaddr;
  bzero(&sockaddr, sizeof(sockaddr));
  sockaddr.sin_family = AF_INET;
  sockaddr.sin_addr.s_addr = inet_addr(m_host.c_str());
  sockaddr.sin_port = htons(m_port);

  //连接服务器
  if (connect(m_sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) == -1)
  {
    Log_Info("socket reconnect failed");
    close(m_sockfd);
    m_sockfd = -1;
    return false;
  }
  Log_Info("socket reconnect success");
  return true;
}


long int CTcpClient::SendDataMaxSize(const void *buff, int bufflen)
{
  if (m_sockfd == -1)
  {
    return 0;
  }

  long int ret = ::send(m_sockfd, buff, bufflen, MSG_NOSIGNAL);
  // 发送失败做补偿处理 ，补发 暂时不用
  if (ret <= 0)
  {
    if (socketConnected(m_sockfd))
    {
      std::this_thread::sleep_for(std::chrono::milliseconds(20));//20
      Log_Info("first send faild");

      //第一次补发，资源可能超限，sleep 1ms让socket缓冲区发送
      ret = ::send(m_sockfd, buff, bufflen, MSG_NOSIGNAL);
      if (ret <= 0)
      {
        std::this_thread::sleep_for(std::chrono::milliseconds(20));//20
        Log_Info("secend send faild");

        //第二次补发
        ret = ::send(m_sockfd, buff, bufflen, MSG_NOSIGNAL);
        if (ret <= 0)
        {
          Log_Info("socket send error, errno={}, errstring:{}", errno, strerror(errno));
        }
      }
    }
    else
    {
      Log_Info("socket disconnect");
    }
  }

  if (ret <= 0)//要统计发送成功字节
  {
    ret = 0;
  }

  return ret;

}

//发送数据到服务器实现 数据量小用这个发
long int CTcpClient::SendData(void *buff, int bufflen)
{
  long int ret = 0;
  if (m_sockfd == -1)
  {
    Log_Info("tcp sockfd is err");
    return 0;
  }

  ret += SendDataMaxSize(buff, bufflen);

  return ret;
}

//接收服务器的数据实现
int CTcpClient ::Recv(void *buff, int bufflen)
{
  if (m_sockfd == -1)
  {
    return 0;
  }
  return recv(m_sockfd, buff, bufflen, 0);
}

bool CTcpClient::socketConnected(int sockfd)
{
  struct tcp_info info;
  int len = sizeof(info);
  if (sockfd <= 0)
  {
    return false;
  }
  int retCI = getsockopt(sockfd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
  (void)retCI;
  return info.tcpi_state == 1;
}

//类的析构函数实现
CTcpClient ::~CTcpClient()
{
  if (m_sockfd != -1) {
      close(m_sockfd);
      m_sockfd = -1;
  }
}

// 移动构造函数实现
CTcpClient::CTcpClient(CTcpClient&& other) noexcept {
    m_sockfd = other.m_sockfd;
    m_host = std::move(other.m_host);
    m_port = other.m_port;
    other.m_sockfd = -1;
}

// 移动赋值运算符实现
CTcpClient& CTcpClient::operator=(CTcpClient&& other) noexcept {
    if (this != &other) {
        close(m_sockfd);
        m_sockfd = other.m_sockfd;
        m_host = std::move(other.m_host);
        m_port = other.m_port;
        other.m_sockfd = -1;
    }
    return *this;
}